Part 1: RNA
Load RNA samples
Out of 30 samples, we selected 18 for this study. These are the normal tissue samples form the control, the UVA and the UVA+SFN treatment groups. normal tissue samples from the UVB_UA groups as well as tumor samples were excluded from this analysis.
First, we removed 7,148 genes with zero counts in > 80% (> 14 out of 18) of samples. 17,273 out of 24,421 genes left.
[1] 7148
[1] 17273
Transcripts per kilobase million (TPM) normalization
Next, we noramized the counts. To convert number of hits to the relative abundane of genes in each sample, we used transcripts per kilobase million (TPM) normalization, which is as following for the j-th sample:
1. normilize for gene length: a[i, j] = 1,000*count[i, j]/gene[i, j] length(bp)
2. normalize for seq depth (i.e. total count): a(i, j)/sum(a[, j])
3. multiply by one million
A very good comparison of normalization techniques can be found at the following video:
RPKM, FPKM and TPM, clearly explained
After the normalization, each sample’s total is 1M:
02w_CON_0 02w_CON_1 02w_SFN_0 02w_SFN_1 02w_UVB_0 02w_UVB_1 15w_CON_0 15w_CON_1 15w_SFN_0 15w_SFN_1 15w_UVB_0 15w_UVB_1 25w_CON_0
1e+06 1e+06 1e+06 1e+06 1e+06 1e+06 1e+06 1e+06 1e+06 1e+06 1e+06 1e+06 1e+06
25w_CON_1 25w_SFN_0 25w_SFN_1 25w_UVB_0 25w_UVB_1
1e+06 1e+06 1e+06 1e+06 1e+06
Top 100 most abundant RNA molecules
# Separate top 100 abundant genes
tmp <- droplevels(tpm[Geneid %in% levels(tpm$Geneid)[(nrow(tpm) - 99):nrow(tpm)]])
tmp <- melt.data.table(data = tmp,
id.vars = 1:2,
measure.vars = 3:ncol(tmp),
variable.name = "Sample",
value.name = "TPM")
tmp$Week <- substr(x = tmp$Sample,
start = 1,
stop = 3)
tmp$Week <- factor(tmp$Week,
levels = unique(tmp$Week))
tmp$Treatment <- substr(x = tmp$Sample,
start = 5,
stop = 7)
tmp$Treatment <- factor(tmp$Treatment,
levels = c("CON",
"UVB",
"SFN"))
tmp$Replica <- substr(x = tmp$Sample,
start = 9,
stop = 9)
tmp$Replica <- factor(tmp$Replica,
levels = 0:1)
# Plot top 100 abundant genes
p2 <- ggplot(tmp,
aes(x = TPM,
y = Geneid,
fill = Treatment,
shape = Week)) +
# facet_wrap(~ Sex, nrow = 1) +
geom_point(size = 3,
alpha = 0.5) +
geom_vline(xintercept = 1,
linetype = "dashed")
ggplotly(p2)
Bottom 100 least abundant RNA molecules
tmp <- droplevels(tpm[Geneid %in% levels(tpm$Geneid)[1:100]])
tmp <- melt.data.table(data = tmp,
id.vars = 1:2,
measure.vars = 3:ncol(tmp),
variable.name = "Sample",
value.name = "TPM")
tmp$Week <- substr(x = tmp$Sample,
start = 1,
stop = 3)
tmp$Week <- factor(tmp$Week,
levels = unique(tmp$Week))
tmp$Treatment <- substr(x = tmp$Sample,
start = 5,
stop = 7)
tmp$Treatment <- factor(tmp$Treatment,
levels = c("CON",
"UVB",
"SFN"))
tmp$Replica <- substr(x = tmp$Sample,
start = 9,
stop = 9)
tmp$Replica <- factor(tmp$Replica,
levels = 0:1)
# Plot top 100 abundant genes
p3 <- ggplot(tmp,
aes(x = TPM,
y = Geneid,
fill = Treatment,
shape = Week)) +
# facet_wrap(~ Sex, nrow = 1) +
geom_point(size = 3,
alpha = 0.5) +
geom_vline(xintercept = 1,
linetype = "dashed")
ggplotly(p3)
PCA of TPM
NOTE: the distributions are skewed. To make them symmetric, log transformation is often applied. However, there is an issue of zeros. In this instance, we added a small values lambda[i] equal to 1/10 of the smallest non-zero value of i-th gene.
dm.tpm <- as.matrix(tpm[, -c(1:2), with = FALSE])
rownames(dm.tpm) <- tpm$Geneid
# # Remove 02w_CON_1 sample and redo PCA
# dm.tpm <- dm.tpm[, colnames(dm.tpm) != "02w_CON_1"]
# dmeta <- dmeta[dmeta$Sample != "02w_CON_1", ]
# Add lambdas to all values, then take a log
dm.ltpm <- t(apply(X = dm.tpm,
MARGIN = 1,
FUN = function(a) {
lambda <- min(a[a > 0])/10
log(a + lambda)
}))
# PCA----
m1 <- prcomp(t(dm.ltpm),
center = TRUE,
scale. = TRUE)
s1 <- summary(m1)
s1
Importance of components:
PC1 PC2 PC3 PC4 PC5 PC6 PC7 PC8 PC9 PC10 PC11 PC12
Standard deviation 70.7928 56.9107 50.8898 28.84564 26.51968 24.81005 23.85276 22.63644 20.97344 20.20442 19.24099 19.01279
Proportion of Variance 0.2901 0.1875 0.1499 0.04817 0.04072 0.03564 0.03294 0.02967 0.02547 0.02363 0.02143 0.02093
Cumulative Proportion 0.2901 0.4777 0.6276 0.67575 0.71647 0.75211 0.78504 0.81471 0.84018 0.86381 0.88524 0.90617
PC13 PC14 PC15 PC16 PC17 PC18
Standard deviation 18.73783 18.53642 17.87923 17.65132 17.16891 2.134e-13
Proportion of Variance 0.02033 0.01989 0.01851 0.01804 0.01707 0.000e+00
Cumulative Proportion 0.92650 0.94639 0.96490 0.98293 1.00000 1.000e+00
Pareto chart of variance explained by principal components
imp <- data.table(PC = colnames(s1$importance),
Variance = 100*s1$importance[2, ],
Cumulative = 100*s1$importance[3, ])
imp$PC <- factor(imp$PC,
levels = imp$PC)
p1 <- ggplot(imp,
aes(x = PC,
y = Variance)) +
geom_bar(stat = "identity",
fill = "grey",
color = "black") +
geom_line(aes(y = rescale(Cumulative,
to = c(min(Cumulative)*30/100,
30)),
group = rep(1, nrow(imp)))) +
geom_point(aes(y = rescale(Cumulative,
to = c(min(Cumulative)*30/100,
30)))) +
scale_y_continuous("% Variance Explained",
breaks = seq(0, 30, by = 5),
labels = paste(seq(0, 30, by = 5),
"%",
sep = ""),
sec.axis = sec_axis(trans = ~.,
name = "% Cumulative Variance",
breaks = seq(0, 30, length.out = 5),
labels = paste(seq(0, 100, length.out = 5),
"%",
sep = ""))) +
scale_x_discrete("") +
theme(axis.text.x = element_text(angle = 90,
hjust = 1))
p1

First 3 principal components, pairwise
# Biplot while keep only the most important variables (Javier)----
# Select PC-s to pliot (PC1 & PC2)
choices <- c(1:3)
# Scores, i.e. points (df.u)
dt.scr <- data.table(m1$x[, choices])
# Add grouping variables
dt.scr$trt <- dmeta$trt
dt.scr$time <- dmeta$time
dt.scr$sample <- dmeta$Sample
# Loadings, i.e. arrows (df.v)
dt.rot <- as.data.frame(m1$rotation[, choices])
dt.rot$feat <- rownames(dt.rot)
dt.rot <- data.table(dt.rot)
# Axis labels
u.axis.labs <- paste(colnames(dt.rot)[choices],
sprintf('(%0.1f%% explained var.)',
100*m1$sdev[choices]^2/sum(m1$sdev^2)))
p1 <- ggplot(data = dt.scr,
aes(x = PC1,
y = PC2,
color = trt,
shape = time)) +
geom_point(size = 4,
alpha = 0.5) +
scale_x_continuous(u.axis.labs[1]) +
scale_y_continuous(u.axis.labs[2])
ggplotly(p1)
p1 <- ggplot(data = dt.scr,
aes(x = PC1,
y = PC3,
color = trt,
shape = time)) +
geom_point(size = 4,
alpha = 0.5) +
scale_x_continuous(u.axis.labs[1]) +
scale_y_continuous(u.axis.labs[3])
ggplotly(p1)
p1 <- ggplot(data = dt.scr,
aes(x = PC2,
y = PC3,
color = trt,
shape = time)) +
geom_point(size = 4,
alpha = 0.5) +
scale_x_continuous(u.axis.labs[2]) +
scale_y_continuous(u.axis.labs[3])
ggplotly(p1)
First 3 principal components, 3D
scatterplot3js(x = dt.scr$PC1,
y = dt.scr$PC2,
z = dt.scr$PC3,
color = as.numeric(dt.scr$trt),
renderer = "auto",
pch = dt.scr$sample,
size = 0.1)
Differential expressions
LS0tDQp0aXRsZTogIlNraW4gVVZCIFNLSDEgbW91c2UgbW9kZWwgdHJlYXRlZCB3aXRoIFNGTiAiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KLS0tDQoNCiMgUGFydCAxOiBSTkENCmBgYHtyIGhlYWRlciwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGVycm9yID0gRkFMU0UsIHdhcm5pbmcgID1GQUxTRX0NCiMgaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJCaW9jTWFuYWdlciIsIHF1aWV0bHkgPSBUUlVFKSkNCiMgICAgIGluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikNCiMgQmlvY01hbmFnZXI6Omluc3RhbGwoIkRFU2VxMiIpDQoNCnJlcXVpcmUoa25pdHIpDQpyZXF1aXJlKGRhdGEudGFibGUpDQpyZXF1aXJlKERUKQ0KcmVxdWlyZShERVNlcTIpDQpyZXF1aXJlKHJlYWR4bCkNCnJlcXVpcmUoQmlvY1BhcmFsbGVsKQ0KcmVxdWlyZShnZ3Bsb3QyKQ0KcmVxdWlyZShwbG90bHkpDQpyZXF1aXJlKHRocmVlanMpDQpyZXF1aXJlKHNjYWxlcykNCg0KIyBOT1RFOiBvbiBERVNlcTIgT3V0cHV0OiAnYmFzZU1lYW4nIGlzIHRoZSBhdmVyYWdlIG9mIHRoZSBub3JtYWxpemVkIGNvdW50IHZhbHVlcywgDQojIGRpdmlkZWQgYnkgdGhlIHNpemUgZmFjdG9ycywgdGFrZW4gb3ZlciBhbGwgc2FtcGxlcyBpbiB0aGUgREVTZXFEYXRhU2V0DQpgYGANCg0KIyMgTG9hZCBSTkEgc2FtcGxlcw0KT3V0IG9mIDMwIHNhbXBsZXMsIHdlIHNlbGVjdGVkIDE4IGZvciB0aGlzIHN0dWR5LiBUaGVzZSBhcmUgdGhlIG5vcm1hbCB0aXNzdWUgc2FtcGxlcyBmb3JtIHRoZSBjb250cm9sLCB0aGUgVVZBIGFuZCB0aGUgVVZBK1NGTiB0cmVhdG1lbnQgZ3JvdXBzLiBub3JtYWwgdGlzc3VlIHNhbXBsZXMgZnJvbSB0aGUgVVZCX1VBIGdyb3VwcyBhcyB3ZWxsIGFzIHR1bW9yIHNhbXBsZXMgd2VyZSBleGNsdWRlZCBmcm9tIHRoaXMgYW5hbHlzaXMuICAgICANCkZpcnN0LCB3ZSByZW1vdmVkIDcsMTQ4IGdlbmVzIHdpdGggemVybyBjb3VudHMgaW4gPiA4MCUgKD4gMTQgb3V0IG9mIDE4KSBvZiBzYW1wbGVzLiAxNywyNzMgb3V0IG9mIDI0LDQyMSBnZW5lcyBsZWZ0LiANCiAgICAgICAgIA0KYGBge3IgZGF0YV9ybmEsIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9DQojIExvYWQgZGF0YS0tLS0NCmR0MCA8LSBmcmVhZCgiZGF0YS9yZW55aV9kZWR1cF9ybmFzZXFfZGF0YS9mZWF0dXJlc2NvdW50c191dmItc2tpbl9kZWR1cF9yZW55aV8yLTktMjAxOC5jc3YiLA0KICAgICAgICAgICAgIHNraXAgPSAxKQ0KDQojIFJlbW92ZSB1bnVzZWQgY29sdW1ucy0tLS0NCmR0MSA8LSBkdDBbLCBjKDEsIDY6bmNvbChkdDApKSwgd2l0aCA9IEZBTFNFXQ0KDQpjbmFtZXMgPC0gY29sbmFtZXMoZHQxKVstYygxOjIpXQ0KY25hbWVzIDwtIGdzdWIoeCA9IGNuYW1lcywNCiAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLmRlZHVwLmJhbSIsDQogICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICIiKQ0KY29sbmFtZXMoZHQxKVstYygxOjIpXSA8LSBjbmFtZXMNCg0KIyBBVFRFTlRJT04hIEluIHRoaXMgYW5hbHlzaXMsIHdlIHdpbGwgb25seSBleGFtaW5lIGNvbnRyb2xzIGFuZCBTRk4NCiMgQWxzbywgcmVtb3ZlZCBjYW5jZXIgY2VsbCBzYW1wbGVzDQp0bmFtZXMgPC0gc3Vic3RyKHggPSBjb2xuYW1lcyhkdDEpLCANCiAgICAgICAgICAgICAgICAgc3RhcnQgPSAzLA0KICAgICAgICAgICAgICAgICBzdG9wID0gMykNCg0KZ25hbWVzIDwtIHN1YnN0cih4ID0gY29sbmFtZXMoZHQxKSwgDQogICAgICAgICAgICAgICAgIHN0YXJ0ID0gNSwNCiAgICAgICAgICAgICAgICAgc3RvcCA9IDcpDQoNCmR0MSA8LSBkdDFbLCBnbmFtZXMgJWluJSBjKCJpZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAidGgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPTiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJTRk4iICkgJg0KICAgICAgICAgICAgIHRuYW1lcyAhPSAidCIsDQogICAgICAgICAgIHdpdGggPSBGQUxTRV0NCiMgMTggc2FtcGxlcyBsZWZ0DQoNCiMgUmVtb3ZlIGdlbmVzIHdpdGggemVybyBjb3VudHMgaW4gPiA4MCUgKD4gMTQgb3V0IG9mIDE4KSBvZiBzYW1wbGVzDQp0bXAgPC0gZHQxWywgLWMoMToyKV0gPT0gMA0KdG1wIDwtIHJvd1N1bXModG1wKSA+IDE0DQpzdW0odG1wKQ0KDQpkdDEgPC0gZHJvcGxldmVscyhkdDFbIXRtcCwgXSkNCm5yb3coZHQxKQ0KIyAxNywyNzMgb3V0IG9mIDI0LDQyMSBnZW5lcyBsZWZ0DQoNCmRhdGF0YWJsZShoZWFkKGR0MSwgMTApLA0KICAgICAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLA0KICAgICAgICAgICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTApLA0KICAgICAgICAgICAgICBjYXB0aW9uID0gIlRhYmxlIDE6IGZpcnN0IDEwIHJvd3Mgb2YgdGhlIGNvdW50IHRhYmxlIikNCmBgYA0KDQojIyBUcmFuc2NyaXB0cyBwZXIga2lsb2Jhc2UgbWlsbGlvbiAoVFBNKSBub3JtYWxpemF0aW9uDQpOZXh0LCB3ZSBub3JhbWl6ZWQgdGhlIGNvdW50cy4gVG8gY29udmVydCBudW1iZXIgb2YgaGl0cyB0byAgdGhlIHJlbGF0aXZlIGFidW5kYW5lIG9mIGdlbmVzIGluIGVhY2ggc2FtcGxlLCB3ZSB1c2VkICoqKnRyYW5zY3JpcHRzIHBlciBraWxvYmFzZSBtaWxsaW9uIChUUE0pKioqIG5vcm1hbGl6YXRpb24sIHdoaWNoIGlzIGFzIGZvbGxvd2luZyBmb3IgdGhlIGotdGggc2FtcGxlOiAgICAgICANCjEuIG5vcm1pbGl6ZSBmb3IgZ2VuZSBsZW5ndGg6IGFbaSwgal0gPSAxLDAwMCpjb3VudFtpLCBqXS9nZW5lW2ksIGpdIGxlbmd0aChicCkgICAgIA0KMi4gbm9ybWFsaXplIGZvciBzZXEgZGVwdGggKGkuZS4gdG90YWwgY291bnQpOiBhKGksIGopL3N1bShhWywgal0pICAgICANCjMuIG11bHRpcGx5IGJ5IG9uZSBtaWxsaW9uICAgICANCkEgdmVyeSBnb29kIGNvbXBhcmlzb24gb2Ygbm9ybWFsaXphdGlvbiB0ZWNobmlxdWVzIGNhbiBiZSBmb3VuZCBhdCB0aGUgZm9sbG93aW5nIHZpZGVvOiAgICANCltSUEtNLCBGUEtNIGFuZCBUUE0sIGNsZWFybHkgZXhwbGFpbmVkXShodHRwczovL3d3dy5ybmEtc2VxYmxvZy5jb20vcnBrbS1mcGttLWFuZC10cG0tY2xlYXJseS1leHBsYWluZWQvKQ0KICAgICANCkFmdGVyIHRoZSBub3JtYWxpemF0aW9uLCBlYWNoIHNhbXBsZSdzIHRvdGFsIGlzIDFNOg0KICAgICANCmBgYHtyIHRwbSwgd2FybmluZyA9IEZBTFNFLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0NCiMgTm9ybWFsaXplIGNvdW50cyB0byBUUE0NCnRtcCA8LSAxMDAwKmR0MVssIDM6bmNvbChkdDEpXS9kdDEkTGVuZ3RoDQp0cG0gPC0gZGF0YS50YWJsZShHZW5laWQgPSBkdDEkR2VuZWlkLA0KICAgICAgICAgICAgICAgICAgTGVuZ3RoID0gZHQxJExlbmd0aCwNCiAgICAgICAgICAgICAgICAgIGFwcGx5KHRtcCwNCiAgICAgICAgICAgICAgICAgICAgICAgIDIsDQogICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbihhKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgIDEwXjYqKGEvc3VtKGEpKQ0KICAgICAgICAgICAgICAgICAgICAgICAgfSkpDQpjb2xTdW1zKHRwbVssIC1jKDE6MildKQ0KDQpmb3JtYXRSb3VuZChkYXRhdGFibGUoaGVhZCh0cG0sIDEwKSwNCiAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCksDQogICAgICAgICAgICAgICAgICAgICAgY2FwdGlvbiA9ICJUYWJsZSAyOiB0cmFuc2NyaXB0cyBwZXIga2lsb2Jhc2UgbWlsbGlvbiAoVFBNKSBub3JtYWxpemVkIGNvdW50cyIpLA0KICAgICAgICAgICAgY29sdW1ucyA9IDM6bmNvbCh0cG0pLA0KICAgICAgICAgICAgZGlnaXRzID0gMikNCg0KIyBUb3RhbCBUUE0NCnRvdGFsIDwtIHJvd1N1bXModHBtWywgMzpuY29sKHRwbSldKQ0KDQojIFNvcnQgZ2VuZXMgYnkgcmVsYXRpdmUgYWJ1bmRhbmN5DQp0cG0kR2VuZWlkIDwtIGZhY3Rvcih0cG0kR2VuZWlkICwNCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHRwbSRHZW5laWRbb3JkZXIodG90YWwsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBGQUxTRSldKQ0KYGBgDQoNCiMgVG9wIDEwMCBtb3N0IGFidW5kYW50IFJOQSBtb2xlY3VsZXMNCmBgYHtyIG1vc3RfYWJ1bmRhbnR9DQojIFNlcGFyYXRlIHRvcCAxMDAgYWJ1bmRhbnQgZ2VuZXMNCnRtcCA8LSBkcm9wbGV2ZWxzKHRwbVtHZW5laWQgJWluJSBsZXZlbHModHBtJEdlbmVpZClbKG5yb3codHBtKSAtIDk5KTpucm93KHRwbSldXSkNCg0KdG1wIDwtIG1lbHQuZGF0YS50YWJsZShkYXRhID0gdG1wLA0KICAgICAgICAgICAgICAgICAgICAgICBpZC52YXJzID0gMToyLA0KICAgICAgICAgICAgICAgICAgICAgICBtZWFzdXJlLnZhcnMgPSAzOm5jb2wodG1wKSwNCiAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGUubmFtZSA9ICJTYW1wbGUiLA0KICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZS5uYW1lID0gIlRQTSIpDQoNCnRtcCRXZWVrIDwtIHN1YnN0cih4ID0gdG1wJFNhbXBsZSwNCiAgICAgICAgICAgICAgICAgICBzdGFydCA9IDEsDQogICAgICAgICAgICAgICAgICAgc3RvcCA9IDMpDQp0bXAkV2VlayA8LSBmYWN0b3IodG1wJFdlZWssDQogICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gdW5pcXVlKHRtcCRXZWVrKSkNCg0KDQp0bXAkVHJlYXRtZW50IDwtIHN1YnN0cih4ID0gdG1wJFNhbXBsZSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gNSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHN0b3AgPSA3KQ0KdG1wJFRyZWF0bWVudCA8LSBmYWN0b3IodG1wJFRyZWF0bWVudCwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkNPTiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNGTiIpKQ0KDQp0bXAkUmVwbGljYSA8LSBzdWJzdHIoeCA9IHRtcCRTYW1wbGUsDQogICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSA5LA0KICAgICAgICAgICAgICAgICAgICAgIHN0b3AgPSA5KQ0KdG1wJFJlcGxpY2EgPC0gZmFjdG9yKHRtcCRSZXBsaWNhLA0KICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IDA6MSkNCg0KIyBQbG90IHRvcCAxMDAgYWJ1bmRhbnQgZ2VuZXMNCnAyIDwtIGdncGxvdCh0bXAsDQogICAgICAgICAgICAgYWVzKHggPSBUUE0sDQogICAgICAgICAgICAgICAgIHkgPSBHZW5laWQsDQogICAgICAgICAgICAgICAgIGZpbGwgPSBUcmVhdG1lbnQsDQogICAgICAgICAgICAgICAgIHNoYXBlID0gV2VlaykpICsNCiAgIyBmYWNldF93cmFwKH4gU2V4LCBucm93ID0gMSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAzLA0KICAgICAgICAgICAgIGFscGhhID0gMC41KSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDEsDQogICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIikNCmdncGxvdGx5KHAyKQ0KYGBgDQoNCiMgQm90dG9tIDEwMCBsZWFzdCBhYnVuZGFudCBSTkEgbW9sZWN1bGVzDQpgYGB7ciBsZWFzdF9hYnVuZGFudH0NCnRtcCA8LSBkcm9wbGV2ZWxzKHRwbVtHZW5laWQgJWluJSBsZXZlbHModHBtJEdlbmVpZClbMToxMDBdXSkNCg0KdG1wIDwtIG1lbHQuZGF0YS50YWJsZShkYXRhID0gdG1wLA0KICAgICAgICAgICAgICAgICAgICAgICBpZC52YXJzID0gMToyLA0KICAgICAgICAgICAgICAgICAgICAgICBtZWFzdXJlLnZhcnMgPSAzOm5jb2wodG1wKSwNCiAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGUubmFtZSA9ICJTYW1wbGUiLA0KICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZS5uYW1lID0gIlRQTSIpDQoNCnRtcCRXZWVrIDwtIHN1YnN0cih4ID0gdG1wJFNhbXBsZSwNCiAgICAgICAgICAgICAgICAgICBzdGFydCA9IDEsDQogICAgICAgICAgICAgICAgICAgc3RvcCA9IDMpDQp0bXAkV2VlayA8LSBmYWN0b3IodG1wJFdlZWssDQogICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gdW5pcXVlKHRtcCRXZWVrKSkNCg0KDQp0bXAkVHJlYXRtZW50IDwtIHN1YnN0cih4ID0gdG1wJFNhbXBsZSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gNSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHN0b3AgPSA3KQ0KdG1wJFRyZWF0bWVudCA8LSBmYWN0b3IodG1wJFRyZWF0bWVudCwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkNPTiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNGTiIpKQ0KDQp0bXAkUmVwbGljYSA8LSBzdWJzdHIoeCA9IHRtcCRTYW1wbGUsDQogICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSA5LA0KICAgICAgICAgICAgICAgICAgICAgIHN0b3AgPSA5KQ0KdG1wJFJlcGxpY2EgPC0gZmFjdG9yKHRtcCRSZXBsaWNhLA0KICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IDA6MSkNCg0KIyBQbG90IHRvcCAxMDAgYWJ1bmRhbnQgZ2VuZXMNCnAzIDwtIGdncGxvdCh0bXAsDQogICAgICAgICAgICAgYWVzKHggPSBUUE0sDQogICAgICAgICAgICAgICAgIHkgPSBHZW5laWQsDQogICAgICAgICAgICAgICAgIGZpbGwgPSBUcmVhdG1lbnQsDQogICAgICAgICAgICAgICAgIHNoYXBlID0gV2VlaykpICsNCiAgIyBmYWNldF93cmFwKH4gU2V4LCBucm93ID0gMSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAzLA0KICAgICAgICAgICAgIGFscGhhID0gMC41KSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDEsDQogICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIikNCmdncGxvdGx5KHAzKQ0KYGBgDQoNCiMgTWV0YSBkYXRhDQpgYGB7ciBtZXRhfQ0KZG1ldGEgPC0gZGF0YS50YWJsZShTYW1wbGUgPSBjb2xuYW1lcyhkdDEpWy1jKDE6MildKQ0KDQpkbWV0YSR0aW1lIDwtIHN1YnN0cih4ID0gZG1ldGEkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gMSwNCiAgICAgICAgICAgICAgICAgICBzdG9wID0gMykNCmRtZXRhJHRpbWUgPC0gZmFjdG9yKGRtZXRhJHRpbWUsDQogICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiMDJ3IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxNXciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjI1dyIpKQ0KZG1ldGEkV2VlayA8LSBmYWN0b3IoZG1ldGEkdGltZSwNCiAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCIwMnciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjE1dyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjV3IiksDQogICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiV2VlayAyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrIDE1IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrIDI1IikpDQoNCmRtZXRhJHRydCA8LSBzdWJzdHIoeCA9IGRtZXRhJFNhbXBsZSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gNSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHN0b3AgPSA3KQ0KZG1ldGEkdHJ0IDwtIGZhY3RvcihkbWV0YSR0cnQsDQogICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDT04iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVWQiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTRk4iKSkNCmRtZXRhJFRyZWF0bWVudCA8LSBmYWN0b3IoZG1ldGEkdHJ0LA0KICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQ09OIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU0ZOIiksDQogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJOZWdhdGl2ZSBDb250cm9sIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBvc2l0aXZlIENvbnRyb2wgKFVWQikiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU3VsZm9yYXBoYW5lIChTRk4pIikpDQoNCmRtZXRhJFJlcGxpY2EgPC0gc3Vic3RyKHggPSBkbWV0YSRTYW1wbGUsDQogICAgICAgICAgICAgICAgICAgICAgc3RhcnQgPSA5LA0KICAgICAgICAgICAgICAgICAgICAgIHN0b3AgPSA5KQ0KZG1ldGEkUmVwbGljYSA8LSBmYWN0b3IoZG1ldGEkUmVwbGljYSwNCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSAwOjEpDQoNCmRhdGF0YWJsZShkbWV0YSwNCiAgICAgICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gbnJvdyhkbWV0YSkpKQ0KYGBgDQoNCiMgUENBIG9mIFRQTQ0KTk9URTogdGhlIGRpc3RyaWJ1dGlvbnMgYXJlIHNrZXdlZC4gVG8gbWFrZSB0aGVtIHN5bW1ldHJpYywgbG9nIHRyYW5zZm9ybWF0aW9uIGlzIG9mdGVuIGFwcGxpZWQuIEhvd2V2ZXIsIHRoZXJlIGlzIGFuIGlzc3VlIG9mIHplcm9zLiBJbiB0aGlzIGluc3RhbmNlLCB3ZSBhZGRlZCBhIHNtYWxsIHZhbHVlcyAqKipsYW1iZGFbaV0qKiogZXF1YWwgdG8gMS8xMCBvZiB0aGUgc21hbGxlc3Qgbm9uLXplcm8gdmFsdWUgb2YgKmkqLXRoIGdlbmUuIA0KYGBge3IgcGNhfQ0KZG0udHBtIDwtIGFzLm1hdHJpeCh0cG1bLCAtYygxOjIpLCB3aXRoID0gRkFMU0VdKQ0Kcm93bmFtZXMoZG0udHBtKSA8LSB0cG0kR2VuZWlkDQoNCiMgIyBSZW1vdmUgMDJ3X0NPTl8xIHNhbXBsZSBhbmQgcmVkbyBQQ0ENCiMgZG0udHBtIDwtIGRtLnRwbVssIGNvbG5hbWVzKGRtLnRwbSkgIT0gIjAyd19DT05fMSJdDQojIGRtZXRhIDwtIGRtZXRhW2RtZXRhJFNhbXBsZSAhPSAiMDJ3X0NPTl8xIiwgXQ0KDQojIEFkZCBsYW1iZGFzIHRvIGFsbCB2YWx1ZXMsIHRoZW4gdGFrZSBhIGxvZw0KZG0ubHRwbSA8LSB0KGFwcGx5KFggPSBkbS50cG0sDQogICAgICAgICAgICAgICAgICAgICAgTUFSR0lOID0gMSwNCiAgICAgICAgICAgICAgICAgICAgICBGVU4gPSBmdW5jdGlvbihhKSB7DQogICAgICAgICAgICAgICAgICAgICAgICBsYW1iZGEgPC0gbWluKGFbYSA+IDBdKS8xMA0KICAgICAgICAgICAgICAgICAgICAgICAgbG9nKGEgKyBsYW1iZGEpDQogICAgICAgICAgICAgICAgICAgICAgfSkpDQoNCiMgUENBLS0tLQ0KbTEgPC0gcHJjb21wKHQoZG0ubHRwbSksDQogICAgICAgICAgICAgY2VudGVyID0gVFJVRSwNCiAgICAgICAgICAgICBzY2FsZS4gPSBUUlVFKQ0KDQpzMSA8LSBzdW1tYXJ5KG0xKQ0KczENCmBgYA0KDQojIFBhcmV0byBjaGFydCBvZiB2YXJpYW5jZSBleHBsYWluZWQgYnkgcHJpbmNpcGFsIGNvbXBvbmVudHMNCmBgYHtyIHBjYV92YXJfcGxvdH0NCmltcCA8LSBkYXRhLnRhYmxlKFBDID0gY29sbmFtZXMoczEkaW1wb3J0YW5jZSksDQogICAgICAgICAgICAgICAgICBWYXJpYW5jZSA9IDEwMCpzMSRpbXBvcnRhbmNlWzIsIF0sDQogICAgICAgICAgICAgICAgICBDdW11bGF0aXZlID0gMTAwKnMxJGltcG9ydGFuY2VbMywgXSkNCmltcCRQQyA8LSBmYWN0b3IoaW1wJFBDLA0KICAgICAgICAgICAgICAgICBsZXZlbHMgPSBpbXAkUEMpDQpwMSA8LSBnZ3Bsb3QoaW1wLA0KICAgICAgICAgICAgIGFlcyh4ID0gUEMsDQogICAgICAgICAgICAgICAgIHkgPSBWYXJpYW5jZSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsDQogICAgICAgICAgIGZpbGwgPSAiZ3JleSIsDQogICAgICAgICAgIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSByZXNjYWxlKEN1bXVsYXRpdmUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdG8gPSBjKG1pbihDdW11bGF0aXZlKSozMC8xMDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDMwKSksDQogICAgICAgICAgICAgICAgZ3JvdXAgPSByZXAoMSwgbnJvdyhpbXApKSkpICsNCiAgZ2VvbV9wb2ludChhZXMoeSA9IHJlc2NhbGUoQ3VtdWxhdGl2ZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG8gPSBjKG1pbihDdW11bGF0aXZlKSozMC8xMDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAzMCkpKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIiUgVmFyaWFuY2UgRXhwbGFpbmVkIiwNCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgwLCAzMCwgYnkgPSA1KSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHBhc3RlKHNlcSgwLCAzMCwgYnkgPSA1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICIiKSwNCiAgICAgICAgICAgICAgICAgICAgIHNlYy5heGlzID0gc2VjX2F4aXModHJhbnMgPSB+LiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICIlIEN1bXVsYXRpdmUgVmFyaWFuY2UiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwgMzAsIGxlbmd0aC5vdXQgPSA1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gcGFzdGUoc2VxKDAsIDEwMCwgbGVuZ3RoLm91dCA9IDUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiJSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICIiKSkpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZSgiIikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpKQ0KcDENCmBgYA0KDQojIEZpcnN0IDMgcHJpbmNpcGFsIGNvbXBvbmVudHMsIHBhaXJ3aXNlDQpgYGB7ciBwY2FfcGxvdHN9DQojIEJpcGxvdCB3aGlsZSBrZWVwIG9ubHkgdGhlIG1vc3QgaW1wb3J0YW50IHZhcmlhYmxlcyAoSmF2aWVyKS0tLS0NCiMgU2VsZWN0IFBDLXMgdG8gcGxpb3QgKFBDMSAmIFBDMikNCmNob2ljZXMgPC0gYygxOjMpDQoNCiMgU2NvcmVzLCBpLmUuIHBvaW50cyAoZGYudSkNCmR0LnNjciA8LSBkYXRhLnRhYmxlKG0xJHhbLCBjaG9pY2VzXSkNCiMgQWRkIGdyb3VwaW5nIHZhcmlhYmxlcw0KZHQuc2NyJHRydCA8LSBkbWV0YSR0cnQNCmR0LnNjciR0aW1lIDwtIGRtZXRhJHRpbWUNCmR0LnNjciRzYW1wbGUgPC0gZG1ldGEkU2FtcGxlDQoNCiMgTG9hZGluZ3MsIGkuZS4gYXJyb3dzIChkZi52KQ0KZHQucm90IDwtIGFzLmRhdGEuZnJhbWUobTEkcm90YXRpb25bLCBjaG9pY2VzXSkNCmR0LnJvdCRmZWF0IDwtIHJvd25hbWVzKGR0LnJvdCkNCmR0LnJvdCA8LSBkYXRhLnRhYmxlKGR0LnJvdCkNCg0KIyBBeGlzIGxhYmVscw0KdS5heGlzLmxhYnMgPC0gcGFzdGUoY29sbmFtZXMoZHQucm90KVtjaG9pY2VzXSwgDQogICAgICAgICAgICAgICAgICAgICBzcHJpbnRmKCcoJTAuMWYlJSBleHBsYWluZWQgdmFyLiknLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMTAwKm0xJHNkZXZbY2hvaWNlc11eMi9zdW0obTEkc2Rldl4yKSkpDQoNCnAxIDwtIGdncGxvdChkYXRhID0gZHQuc2NyLA0KICAgICAgICAgICAgIGFlcyh4ID0gUEMxLA0KICAgICAgICAgICAgICAgICB5ID0gUEMyLA0KICAgICAgICAgICAgICAgICBjb2xvciA9IHRydCwNCiAgICAgICAgICAgICAgICAgc2hhcGUgPSB0aW1lKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSA0LA0KICAgICAgICAgICAgIGFscGhhID0gMC41KSArDQogIHNjYWxlX3hfY29udGludW91cyh1LmF4aXMubGFic1sxXSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModS5heGlzLmxhYnNbMl0pDQpnZ3Bsb3RseShwMSkNCg0KcDEgPC0gZ2dwbG90KGRhdGEgPSBkdC5zY3IsDQogICAgICAgICAgICAgYWVzKHggPSBQQzEsDQogICAgICAgICAgICAgICAgIHkgPSBQQzMsDQogICAgICAgICAgICAgICAgIGNvbG9yID0gdHJ0LA0KICAgICAgICAgICAgICAgICBzaGFwZSA9IHRpbWUpKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDQsDQogICAgICAgICAgICAgYWxwaGEgPSAwLjUpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKHUuYXhpcy5sYWJzWzFdKSArDQogIHNjYWxlX3lfY29udGludW91cyh1LmF4aXMubGFic1szXSkNCmdncGxvdGx5KHAxKQ0KDQpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGR0LnNjciwNCiAgICAgICAgICAgICBhZXMoeCA9IFBDMiwNCiAgICAgICAgICAgICAgICAgeSA9IFBDMywNCiAgICAgICAgICAgICAgICAgY29sb3IgPSB0cnQsDQogICAgICAgICAgICAgICAgIHNoYXBlID0gdGltZSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gNCwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuNSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXModS5heGlzLmxhYnNbMl0pICsNCiAgc2NhbGVfeV9jb250aW51b3VzKHUuYXhpcy5sYWJzWzNdKQ0KZ2dwbG90bHkocDEpDQpgYGANCg0KIyBGaXJzdCAzIHByaW5jaXBhbCBjb21wb25lbnRzLCAzRA0KYGBge3IgcGNhXzNkLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEwfQ0Kc2NhdHRlcnBsb3QzanMoeCA9IGR0LnNjciRQQzEsIA0KICAgICAgICAgICAgICAgeSA9IGR0LnNjciRQQzIsIA0KICAgICAgICAgICAgICAgeiA9IGR0LnNjciRQQzMsIA0KICAgICAgICAgICAgICAgY29sb3IgPSBhcy5udW1lcmljKGR0LnNjciR0cnQpLA0KICAgICAgICAgICAgICAgcmVuZGVyZXIgPSAiYXV0byIsDQogICAgICAgICAgICAgICBwY2ggPSBkdC5zY3Ikc2FtcGxlLA0KICAgICAgICAgICAgICAgc2l6ZSA9IDAuMSkNCmBgYA0KDQoNCiMgRGlmZmVyZW50aWFsIGV4cHJlc3Npb25zDQpgYGB7ciBkZXNlcTJ9DQoNCmBgYA0KDQoNCiMgU2Vzc2lvbiBJbmZvcm1hdGlvbg0KYGBge3IgaW5mbyxldmFsPVRSVUV9DQpzZXNzaW9uSW5mbygpDQpgYGA=